#version 330

#define MOD 0
#define XOR 1
#define SXOR 2

const float float_precision_threshold = 0.1;

in vec3 oPos;
in vec3 oCol;
in vec3 oNormal;
in vec2 oTexCoord;

uniform int uGridGenType;       // 网格生成算法类型
uniform float uGridAmbient;     // 网格的环境光调节系数
uniform vec4 uGridScale;        // 网格的尺度：宽高，单个网格的size（分别控制宽高的size）
uniform vec3 uGridColorA;       // 网格交替颜色
uniform vec3 uGridColorB;

out vec4 oFragColor;

void main() {
    // mod/xor的本质就是将传入的坐标转化为0-1信号，但是这种离散信号会导致强烈的噪点，尤其是远处网格的位置
    if (uGridGenType == MOD) {
        vec2 cell = floor(oPos.xz / uGridScale.zw);
        float mod = mod(cell.x + cell.y, 2.);
        vec3 col = mix(uGridColorA, uGridColorB, mod);
        oFragColor = vec4(uGridAmbient * col, 1.);
    } else if (uGridGenType == XOR) {
        // xor的性质：1. a^b=b^a 2. a^0=0^a=a 3. a^a=0, 这里设置的cell中偏移了0.1主要因为浮点数的精度问题导致的误差，可以通过uniform外部传递进来控制
        // glsl提供的round和floor的区别：前者是四舍五入，后者直接丢弃小数掉，只有对角的cell.x == cell.y, 所以针对网格的对角格，xor之后的结果为0
        // 对角上下均为非0态，通过&1将异或值限制在01
        ivec2 cell = ivec2(round(oPos.xz + float_precision_threshold));
        float xor = float((cell.x ^ cell.y) & 1);
        vec3 col = mix(uGridColorA, uGridColorB, xor);
        oFragColor = vec4(uGridAmbient * col, 1.);
    } else if (uGridGenType == SXOR) {
        // 将0-1离散信号转化为连续的三角信号，能优化一部分上面的噪点问题，目前还是比较严重
        vec2 cell = sign(fract(oPos.xz) - 0.5);
        float sxor = 0.5 - 0.5 * cell.x * cell.y;
        vec3 col = mix(uGridColorA, uGridColorB, sxor);
        oFragColor = vec4(uGridAmbient * col, 1.);
    }
}
